﻿using System;
using System.Drawing;
using System.ComponentModel;
using System.Runtime.Serialization;

using SharpGL.Media3D;
using SharpGL.SceneGraph.Helpers;

namespace SharpGL.SceneGraph.Primitives.Text
{
    /// <summary>
    /// A text object text in specified point.
    /// </summary>
    [DataContract(IsReference = true)]
    public abstract class TextObject : SceneElement, IRenderable, IFreezable, IVolumeBound
    {
        #region Private Fields

        /// <summary>
        /// The freezable helper.
        /// </summary>
        private FreezableHelper freezableHelper = new FreezableHelper();

        /// <summary>
        /// The bounding volume helper - used for implementation of IBoundVolume.
        /// </summary>
        private BoundingVolumeHelper boundingVolumeHelper = new BoundingVolumeHelper();

        /// <summary>
        /// The text position.
        /// </summary>
        private Point3D position = new Point3D();

        /// <summary>
        /// The text font.
        /// </summary>
        private Font font = new Font("Arial", 3.0f);
        
        /// <summary>
        /// The text.
        /// </summary>
        private string text = "";

        #endregion Private Fields

        #region Protected Methods

        /// <summary>
        /// Perform all rendering operation to the provided instance of OpenGL.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        /// <param name="renderMode">The render mode.</param>
        protected abstract void InternalRenderText(OpenGL gl, RenderMode renderMode);

        /// <summary>
        /// Call this function to do the PropertyChanged event.
        /// </summary>
        protected override void NotifyPropertyChanged(string propertyName)
        {
            UpdateBoundingVolume();

            base.NotifyPropertyChanged(propertyName);
        }

        protected virtual void UpdateBoundingVolume()
        {
            boundingVolumeHelper.BoundingVolume.FromVertices(new Point3D[] { Position });
        }

        #endregion Protected Methods

        #region Public Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="TextObject"/> class.
        /// </summary>
        public TextObject() 
		{
			Name = "Text object";
            UpdateBoundingVolume();
		}

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Render to the provided instance of OpenGL.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        /// <param name="renderMode">The render mode.</param>
        public virtual void Render(OpenGL gl, RenderMode renderMode)
        {
            if (OpenGL.IsValidContext(gl))
            {
                // If we're frozen, use the helper.
                if (freezableHelper.IsFrozen)
                {
                    freezableHelper.Render();
                }
                else
                {
                    InternalRenderText(gl, renderMode);
                }
            }
        }

		/// <summary>
        /// Freezes this instance using the provided OpenGL instance.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        public virtual void Freeze(OpenGL gl)
        {
            //  Freeze using the helper.
            freezableHelper.Freeze(gl, this);
        }

        /// <summary>
        /// Unfreezes this instance using the provided OpenGL instance.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        public virtual void Unfreeze(OpenGL gl)
        {
            //  Unfreeze using the helper.
            freezableHelper.Unfreeze();
        }

        #endregion Public Methods

        #region Propetries

        /// <summary>
        /// Gets the bounding volume.
        /// </summary>
        [Browsable(false)]
        public BoundingVolume BoundingVolume
        {
            get { return boundingVolumeHelper.BoundingVolume; }
        }
        
        /// <summary>
        /// Gets a value indicating whether this instance is frozen.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance is frozen; otherwise, <c>false</c>.
        /// </value>
        [Browsable(false)]
        public bool IsFrozen
        {
            get
            {
                return freezableHelper.IsFrozen;
            }
        }
        
        /// <summary>
        /// Gets or sets the text position.
        /// </summary>
        /// <value>
        /// The text position.
        /// </value>
        [Description("The text position."), Category("Text object")]
		public Point3D Position
		{
            get { return position; }
            set
            {
                if (position != value)
                {
                    position = value;

                    NotifyPropertyChanged("Position");
                }
            }
		}

        /// <summary>
        /// Gets or sets the text font.
        /// </summary>
        /// <value>
        /// The text font.
        /// </value>
        [Description("The font."), Category("Text object")]
        public Font Font
        {
            get { return font; }
            set
            {
                if (!font.Equals(value))
                {
                    font = (Font)value.Clone();

                    NotifyPropertyChanged("Font");
                }
            }
        }

        /// <summary>
        /// Gets or sets the text.
        /// </summary>
        /// <value>
        /// The text.
        /// </value>
        [Description("The text."), Category("Text object")]
        public string Text
        {
            get { return text; }
            set
            {
                if (text != value)
                {
                    text = value;

                    NotifyPropertyChanged("Text");
                }
            }
        }

        #endregion
    }
}
